<!--
 * @Author: zhangjingyu
 * @Date: 2020-10-22 19:30:00
 * @LastEditors: zhangjingyu
 * @LastEditTime: 2021-04-28 14:43:59
 * @FilePath: \vprisk10.14\src\views\SystemMange\menuManage.vue
 * @Description: 菜单管理
-->

<template>
  <!-- 菜单管理页面 -->
  <div>
    <el-row class="caliberHierarchy container">
      <el-col style="margin-right:10px;" class="content-left">
        <el-row class="handleBox">
          <el-col :span="18">
            <el-button @click="addFunc">新增</el-button>
            <el-button @click="editFunc">编辑</el-button>
            <el-button @click="delFunc">删除</el-button>
            <el-button @click="menuConfig">配置</el-button>
          </el-col>
          <el-col :span="6">
            <div class="handleIconBox">
              <el-popover
                placement="left-start"
                trigger="click"
                popper-class="icon_porper"
              >
                <onlyOneSearch
                  v-model="searchForm.menuName"
                  placeholder="请输入菜单名"
                  :search-method="searchFunc"
                ></onlyOneSearch>
                <i
                  class="iconfont icon-sousuo"
                  title="搜索"
                  slot="reference"
                ></i>
              </el-popover>
              <el-popover
                placement="bottom"
                width="150"
                trigger="click"
                popper-class="icon_porper"
              >
                <div class="operation_checkbox">
                  <el-checkbox-group v-model="checkList">
                    <el-checkbox
                      v-for="item in textData"
                      :label="item.label"
                      :key="item.prop"
                      >{{ item.label }}
                    </el-checkbox>
                  </el-checkbox-group>
                </div>
                <i
                  class="iconfont icon-liebiaoshezhi"
                  title="列表设置"
                  slot="reference"
                ></i>
              </el-popover>
            </div>
          </el-col>
        </el-row>
        <el-table
          ref="multipleTable"
          :data="tableData"
          row-key="menuId"
          default-expand-all
          @row-click="tableClickFunc"
          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
          style="width: 100%"
          @select-all="selectAll"
          @select="selectRow"
        >
          <el-table-column
            width="55"
            type="selection"
          ></el-table-column>

          <el-table-column
            prop="menuName"
            label="菜单名称"
            v-if="columnState[0]"
            show-overflow-tooltip
          >
          </el-table-column>
          <el-table-column
            prop="menuCode"
            label="菜单编码"
            v-if="columnState[1]"
          >
          </el-table-column>
          <el-table-column
            prop="menuType"
            label="菜单类型"
            v-if="columnState[2]"
            :formatter="menuTypeFormat"
          >
          </el-table-column>

          <el-table-column
            prop="menuUrl"
            label="菜单路径"
            v-if="columnState[3]"
            show-overflow-tooltip
          >
          </el-table-column>
          <el-table-column
            prop="iconName"
            label="菜单图标"
            v-if="columnState[4]"
            align="center"
          >
            <template slot-scope="scope">
              <i :class="scope.row.iconName"></i>
            </template>
          </el-table-column>
          <el-table-column
            prop="funcdesc"
            label="菜单描述"
            v-if="columnState[5]"
            show-overflow-tooltip
          >
          </el-table-column>
          <el-table-column
            prop="moduleCode"
            label="所属模块"
            :formatter="moeuleFormat"
            v-if="columnState[6]"
          >
          </el-table-column>
        </el-table>
      </el-col>
    </el-row>
    <el-dialog
      v-dialogDrag
      :title="saveTitles[saveFlg - 1]"
      :visible.sync="addOrEdit"
      width="514px"
    >
      <el-form
        :model="saveForm"
        ref="saveForm"
        label-width="97px"
        label-position="left"
        :rules="saveFormRules"
      >
        <el-col :span="24">
          <el-form-item label="菜单名称：" prop="menuName">
            <el-input v-model="saveForm.menuName" maxlength="40"></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="24">
          <el-form-item label="菜单编码：" prop="menuCode">
            <el-input v-model="saveForm.menuCode" maxlength="40"></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="24">
          <el-form-item label="上级菜单：" prop="pId">
            <el-cascader
              clearable
              filterable
              :options="options"
              v-model="saveForm.pId"
              :props="{
                checkStrictly: true,
                emitPath: false,
                value: 'menuId',
                label: 'menuName'
              }"
              :show-all-levels="false"
              ref="menuTree"
              style="width:100%"
              @change="checkMenuTree"
            ></el-cascader>
          </el-form-item>
        </el-col>

        <el-col :span="24">
          <el-form-item label="菜单描述：" prop="funcdesc">
            <el-input v-model="saveForm.funcdesc" maxlength="200"></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="菜单类型：" prop="menuType">
            <el-select v-model="saveForm.menuType" placeholder="请选择">
              <el-option
                v-for="item in menuTypeList"
                :key="item.value"
                :value="item.value"
                :label="item.label"
              ></el-option>
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :offset="1" :span="11">
          <el-form-item label="所属模块：" prop="moduleCode">
            <el-select v-model="saveForm.moduleCode" placeholder="请选择">
              <el-option
                v-for="item in moduleList"
                :key="item.moduleCode"
                :value="item.moduleCode"
                :label="item.moduleName"
              ></el-option>
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="24" v-if="saveForm.menuType == '1'">
          <el-form-item label="菜单URL：" prop="menuUrl">
            <el-input v-model="saveForm.menuUrl" maxlength="255"></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="24" v-if="saveForm.menuType == '1'">
          <el-form-item label="权限范围：" prop="permissionKey">
            <el-select
              v-model="saveForm.permissionKey"
              placeholder="请选择"
              filterable
              style="width:100%"
            >
              <el-option
                v-for="item in permissionKeyList"
                :key="item.value"
                :value="item.value"
                :label="item.label"
              ></el-option>
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="24">
          <el-form-item label="菜单图标：" prop="iconName">
            <i
              :class="saveForm.iconName"
              style="font-size:20px;margin-right:20px;"
            ></i>
            <el-button @click="iconCardShow = true">配置菜单图标</el-button>
          </el-form-item>
        </el-col>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="saveFunc">确 定</el-button>
        <el-button @click="addOrEdit = false">取 消</el-button>
      </div>

      <el-dialog
        v-dialogDrag
        title="选择图标"
        width="40%"
        :visible.sync="iconCardShow"
        append-to-body
      >
        <el-card class="iconcard" style="overflow:auto;height:450px">
          <el-button
            size="mini"
            v-for="item in iconList"
            :icon="'iconfont icon-' + item.font_class"
            :key="item.icon_id"
            style="margin:10px"
            @click="iconCheck('iconfont icon-' + item.font_class)"
            :title="item.name"
          ></el-button>
        </el-card>
      </el-dialog>
    </el-dialog>
    <!-- <el-button type="normal" @click="getModuleList">123</el-button> -->
    <el-dialog
      v-dialogDrag
      :title="'配置菜单位置和层级'"
      :visible.sync="isMenuConfig"
      width="514px"
      class="menuConf"
    >
      <vp-tree
        vp-title="菜单移动"
        :data="tableData"
        :props="{
          children: 'children',
          label: 'menuName',
          value: 'menuId'
        }"
        ref="menuConfigTree"
        node-key="menuId"
        :default-expand-all="false"
        draggable
        :expand-on-click-node="true"
        :allow-drop="allowDrop"
        :allow-drag="allowDrag"
        @node-drag-end="arterDrop"
      ></vp-tree>
      <div slot="footer"></div>
    </el-dialog>
  </div>
</template>

<script>
import { systemManage } from "@/api/index";
import onlyOneSearch from "@/components/onlyOneSearch";
import moment from "moment";
import { listToTree } from "@/lib/util";
import iconList from "../../assets/icon/font/iconfont.json";
import { getDict } from "@/api/getDict"; // 字典接口
import { getLabel } from "@/lib/util";
export default {
  data() {
    return {
      userName: "", //右侧用户名
      addOrEdit: false, // 新增/编辑/查看弹窗
      iconCardShow: false, // 图标弹窗
      isMenuConfig: false,
      checkedKeys: false, // 是否全选
      saveFlg: 1, // 1:新增，2：编辑，3查看,
      saveTitles: ["添加菜单", "编辑菜单"],
      iconList: [],
      // 机构树
      orgList: [
        {
          value: "01",
          label: "一级机构",
          children: [{ value: "001", label: "二级机构" }]
        }
      ],
      options: [],
      moduleDataForm: {},
      // 菜单类型下拉框
      menuTypeList: [],
      // 所属模块下拉框
      moduleList: [],
      // 所属模块字典项
      moduleListAll: [],
      // 权限范围字典
      permissionKeyList: [],
      searchForm: {
        menuName: "",
        page: 1,
        size: 15
      },
      total: 0,
      saveForm: {
        menuId: "",
        menuName: "",
        menuCode: "",
        menuType: "",
        menuUrl: "",
        iconName: "iconfont icon-caidanguanli",
        funcdesc: "",
        moduleCode: "",
        pId: ""
      },
      saveFormRules: {
        menuName: [
          { required: true, message: "该输入项为必输项", trigger: "blur" }
        ],
        menuCode: [
          { required: true, message: "该输入项为必输项", trigger: "blur" },
          {
            pattern: /^[0-9a-zA-Z_]{0,40}$/,
            message: "只能输入40位以内的英文字母、数字、下划线字符",
            trigger: "blur"
          }
        ],
         pId: [
          { validator: this.pIdValid, trigger: "change" }
        ],
        menuUrl: [
          { required: true, message: "该输入项为必输项", trigger: "blur" }
        ],
        menuType: [
          { required: true, message: "该输入项为必输项", trigger: "blur" }
        ],
        moduleCode: [
          { required: true, message: "该输入项为必输项", trigger: "blur" }
        ],
        funcdesc: [{ validator: this.funcdescValid, trigger: "blur" }]
        //  permissionKey:[
        //     { required: true, message: "该输入项为必选项", trigger: "blur" },
        //  ]
      },
      checkList: [],
      // 列属性配置
      textData: [
        { prop: "name", label: "菜单名称" },
        { prop: "menuCode", label: "菜单编码" },
        { prop: "menuType", label: "菜单类型" },
        { prop: "url", label: "菜单URL" },
        { prop: "icon", label: "菜单图标" },
        { prop: "funcdesc", label: "菜单描述" },
        { prop: "moduleCode", label: "所属模块" }
      ],
      // 获取table的数据
      tableData: []
    };
  },
  components: {
    onlyOneSearch
  },
  created() {
    
    this.checkListInit();
    // console.log(this.tableData, "模拟数据");
  },
  computed: {
    columnState() {
      // console.log(this.checkList);
      let arr = [],
        arr1 = this.textData,
        arr2 = this.checkList;
      for (let i = 0; i < arr1.length; i++) {
        let flg = false;
        for (let j = 0; j < arr2.length; j++) {
          if (arr1[i].label === arr2[j]) {
            flg = true;
          }
        }
        arr.push(flg);
      }
      return arr;
    }
  },
  mounted() {
    // this.getList();
    this.getIconList();
    this.getModuleList();
    this.getDIct();
    this.$nextTick(() => {
      this.searchFunc();
       // 设置当前页面路由为缓存路由
    if(!this.$route.meta.keepAlive){
      this.$route.meta.keepAlive = true
    };
    });
  },
  watch: {
    addOrEdit() {
      // 窗口打开或关闭清除校验结果
      if (this.$refs.saveForm) {
        this.$refs.saveForm.clearValidate();
      }
    }
  },
  methods: {
    // 获取字典
    getDIct() {
      let dictObj = {
        moduleListAll: "sys_moduleCode", // 所属模块
        menuTypeList: "sys_menuType", // 菜单类型
        permissionKeyList: "PERMISSION_KEY" // 权限范围
      };
      for (const k in dictObj) {
        getDict(dictObj[k]).then(res => {
          if (res.code == 200) {
            this[k] = res.datas;
          }
        });
      }
    },
    // 获取图标列表
    getIconList() {
      this.iconList = iconList.glyphs;
    },
    // 获取moduleList
    getModuleList() {
      systemManage.queryAllEnableModules().then(res => {
        if (res && res.code == 200) {
          this.moduleList = res.datas;
        }
        // console.log(res);
      });
    },
    checkListInit() {
      this.checkList = this.textData.map(v => {
        return v.label;
      });
    },
    // 全选无法全部选择处理
    selectAll() {
      this.checkedKeys = !this.checkedKeys;
      // 处理数据函数
      this.spliteFunc(this.tableData, this.checkedKeys);
    },
    selectRow(selection, row) {
      // console.log(row)
      row.isChecked = !row.isChecked;
      this.spliteFunc(selection, row.isChecked);
    },
    spliteFunc(data, flag) {
      data.forEach(row => {
        this.$refs.multipleTable.toggleRowSelection(row, flag);
        if (row.children != undefined) {
          this.spliteFunc(row.children, flag);
        }
      });
    },
    // 选择上级菜单事件
    checkMenuTree() {
      this.$refs.menuTree.dropDownVisible = false;
    },
    pIdValid(rule, value, callback){
      if(this.saveForm.menuId==''){
        callback();
        return;
      }
      if(value == this.saveForm.menuId){
        callback(new Error("上级菜单不能是自身"));
      }else{
        callback();
      }
    },
    funcdescValid(rule, value, callback) {
      if (
        value.indexOf("<") != -1 ||
        value.indexOf(">") != -1 ||
        value.indexOf("!") != -1 ||
        value.indexOf("'") != -1 ||
        value.indexOf('"') != -1
      ) {
        callback(new Error("只能输入0-256个字符，不允许输入>、<、'、\""));
      } else {
        callback();
      }
    },
    searchFunc() {
      console.log(this.searchForm);
      systemManage.meunManageQuery(this.searchForm).then(res => {
        let filterData = this.filterMenuByName(
          this.searchForm.menuName,
          res.datas
        );
          for (let i = 0; i < filterData.length; i++) {
          filterData[i].disabled = filterData[i].menuType=='1'
        }
        let tree = listToTree("menuId", "parentMenuId", filterData);
        this.tableData = tree;
        // 上级菜单树用全部可选菜单树
        if(this.searchForm.menuName==''){
       let options = this.$clone(tree);
        this.options = options;
        }
      });
    },
    // 过滤所有菜单list，根据查询条件
    filterMenuByName(name, list) {
      if (!name) return list;
      let filterData = [];
      for (let i = 0; i < list.length; i++) {
        if (list[i].menuName.indexOf(name) !== -1) {
          filterData.push(list[i]);
        }
      }
      return filterData;
    },
    addFunc() {
      this.saveFlg = 1;
      for (let k in this.saveForm) {
        this.saveForm[k] = "";
      }
      this.addOrEdit = true;
      this.$nextTick(() => {
        // 清除校验结果
        this.$refs.saveForm.clearValidate();
      });
    },
    editFunc() {
      this.saveFlg = 2;
      let selection = this.$refs.multipleTable.selection;
      if (selection.length != 1) {
        return this.$message.warning("请选择一条数据进行修改");
      }
      let row = selection[0];
      let form = { ...row };
      form.pId = row.parentMenuId;
      this.saveForm = form;
      this.addOrEdit = true;
    },
    // 保存
    saveFunc() {
      this.$refs["saveForm"].validate(valid => {
        if (valid) {
          let data = {
            parentId: this.saveForm.pId,
            menuDTO: { ...this.saveForm }
          };
          delete data.menuDTO.pId;

          if (!data.parentId) {
            data.parentId = "-1";
          }
          data.menuDTO.menuUrl = data.menuDTO.menuUrl.replace(/\\/g,'\/')
          systemManage
            .meunManageSave(data)
            .then(res => {
              if (res.code == 200) {
                this.$message.success("保存成功");
                this.addOrEdit = false;
                this.searchFunc();
              } else {
                this.$message.error(res.message);
              }
            })
            .catch(err => {});
        }
      });
    },
    delFunc() {
      let val = "删除";
      let selection = this.$refs.multipleTable.selection;
      if (selection.length != 1) {
        return this.$message.warning("请选择一项要" + val + "的菜单项");
      }
      this.$confirm(`您确定要${val}所选菜单吗?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      })
        .then(() => {
          let data = { menuId: selection[0].menuId };
          systemManage.meunManageRemove(data).then(res => {
            if (res.code == 200) {
              this.$message.success(val + "成功");
              this.searchFunc();
            }
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消" + val
          });
        });
    },
    // 处理选择图标点击事件
    iconCheck(icon) {
      this.saveForm.iconName = icon;
      this.iconCardShow = false;
    },
    menuTypeFormat(row) {
      return getLabel(row.menuType, this.menuTypeList);
    },
    moeuleFormat(row) {
      return getLabel(row.moduleCode, this.moduleListAll);
    },
    timeFormat(val) {
      return moment(val).format("YYYY-MM-DD");
    },
    tableClickFunc(row) {
      this.$refs.multipleTable.clearSelection();
      this.$refs.multipleTable.toggleRowSelection(row, true);
    },
    menuConfig() {
      this.isMenuConfig = true;
    },
    // 节点是否可被拖拽
    allowDrag(node) {
      return node.data.menuId != "-1";
    },
    // 节点是否可被放置
    allowDrop(mouseNode, toNode, type) {
      // console.log(toNode, "tonode", type);
      // 菜单内不可放置，菜单组内才能放置
      if (toNode.data.menuType === "1") {
        return type !== "inner";
        // 不能在模块层放置菜单
      // }else if(toNode.data.parentMenuId==='-1'){
        // return type === "inner"
      } else {
        return true;
      }
    },
    // 拖拽完成
    arterDrop(mouseNode, toNode, type, event) {
      let typeInfo =
        type === "inner" ? "之中" : type === "after" ? "之后" : "之前";
      console.log(type);
      this.$confirm(
        `您确定要将【${mouseNode.data.menuName}】移动到【${toNode.data.menuName}】${typeInfo}吗？`,
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }
      )
        .then(() => {
          let moveType =
            type === "after" ? "next" : type === "before" ? "prev" : "inner";
          let data = {
            currId: mouseNode.data.menuId,
            toId: toNode.data.menuId,
            moveType: moveType
          };
          systemManage.meunManageMoveMenu(data).then(res => {
            if (res.code == 200) {
              // 判断父节点是否变动
              this.$message.success("菜单移动成功，重新登录后生效。");
              this.searchFunc();
              if (type === "inner") {
                this.$alert("因父节点有变动，需要重新授权菜单。", "提示", {
                  confirmButtonText: "确定"
                });
              }
              if (
                type != "inner" &&
                mouseNode.data.parentMenuId != toNode.data.parentMenuId
              ) {
                this.$alert("因父节点有变动，需要重新授权菜单。", "提示", {
                  confirmButtonText: "确定"
                });
              }
            } else {
              this.$message.error(res.message || "菜单移动失败");
              this.searchFunc();
            }
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消菜单移动"
          });
          this.searchFunc();
        });
    }
  }
};
</script>

<style lang="scss" scoped>
.menuConf /deep/ .el-dialog__body {
  max-height: 100%;
}
</style>